<?php
/**************************************************************************
 *
 *   Copyright 2010 American Public Media Group
 *
 *   This file is part of AIR2.
 *
 *   AIR2 is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   AIR2 is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with AIR2.  If not, see <http://www.gnu.org/licenses/>.
 *
 *************************************************************************/

require_once 'air2writer/YamlWriter.php';
require_once 'air2validator/ColumnCountValidator.php';
require_once 'air2validator/DoctrineTableValidator.php';

/**
 * CSV Yaml Data Importer
 *
 * A YamlWriter customized to load all the related tables used in a CSV import.
 *
 * @author rcavis
 * @package default
 */
class CSVYamlWriter extends YamlWriter {
    protected $headers;
    protected $ini;
    protected $map_facts;
    protected $col_valids = array();

    /* track number of facts written */
    protected $num_facts_written = 0;


    /**
     * Constructor
     *
     * Make sure temp-file directory is writable.
     *
     * @param Tank    $t
     * @param array   $ini
     * @param unknown $csv_headers
     */
    function __construct(Tank $t, $ini, $csv_headers) {
        // check directory
        $dir = $t->get_folder_path().'/yaml';
        air2_rmdir($dir); // clean any old files
        if (!air2_mkdir($dir) || !is_writable($dir)) {
            throw new Exception("Unable to create/write directory $dir");
        }
        $this->output_dir = $dir;
        $this->ini = $ini;
        $this->headers = $csv_headers;

        // create the mapping config
        $config = array(
            'TankSource' => array(
                'tsrc_tank_id' => array('val' => $t->tank_id),
                'tsrc_cre_user' => array('val' => $t->tank_cre_user),
                'tsrc_upd_user' => array('val' => $t->tank_upd_user),
                'tsrc_cre_dtim' => array('val' => air2_date()),
                'tsrc_upd_dtim' => array('val' => air2_date()),
            ),
            'TankFact' => array(

            ),
        );

        // setup mapping
        foreach ($csv_headers as $idx => $col) {
            // only tank_fld mappings... others will be picked up manually
            $def = $ini[$col];
            if (isset($def['tank_fld'])) {
                $this->col_valids[] = "TankSource:".$def['tank_fld'];
                $config['TankSource'][$def['tank_fld']] = array('map' => $idx);
            }
        }
        $this->config = $config;

        // cache fact mappings from headers
        $this->cache_fact_mappings($csv_headers, $ini);
    }


    /**
     * Override to provide our own validators
     *
     * @param AIR2_Reader $reader
     * @param array   $validators (optional)
     * @return int the number of items successfully written
     */
    public function write_data(AIR2_Reader $reader, $validators=array()) {
        $validators[] = new ColumnCountValidator(count($this->headers));
        $validators[] = new DoctrineTableValidator($this->col_valids);
        return parent::write_data($reader, $validators);
    }


    /**
     * Cache any fact mappings in the csv header
     *
     * @param array   $headers
     * @param array   $ini
     */
    protected function cache_fact_mappings($headers, $ini) {
        $conn = AIR2_DBManager::get_connection();
        $q = 'select fact_id from fact where fact_name = ?';

        // cache the column indexes of any facts
        $this->map_facts = array();
        foreach ($headers as $idx => $col) {
            $def = $ini[$col];
            if (isset($def['tank_fact_fld'])) {
                // lookup the fact_id
                $fid = $conn->fetchOne($q, array($col), 0);
                if (!$fid) {
                    throw new Exception("Unknown Fact type '$col'");
                }
                else {
                    $this->map_facts[$idx] = array(
                        'fact_id' => $fid,
                        'fact_name' => $col,
                        'tank_fact_fld' => $def['tank_fact_fld'],
                    );
                }
            }
        }
    }


    /**
     * Check each yaml object for Fact data
     *
     * @param array   $obj       data to write
     * @param array   $modelname model to write to
     * @param int     $idx       object number we're writing
     * @param array   $fields    field mapping def
     */
    protected function write_yaml($obj, $modelname, $idx, $fields) {
        if ($modelname == 'TankFact') {
            // determine if there are any facts to write
            $str = '';
            foreach ($this->map_facts as $colidx => $fmap) {
                // ignore empty strings/nulls
                $fdata = $obj[$colidx];
                if ($fdata) {
                    $this->num_facts_written++;
                    $str.= "  TankFact_$idx"."_$colidx:\n";
                    $str.= "    TankSource: TankSource_$idx\n";
                    $str.= "    tf_fact_id: ".$fmap['fact_id']."\n";
                    $str.= "    ".$fmap['tank_fact_fld'].": $fdata\n";
                }
            }
            fwrite($this->outfiles['TankFact'], $str);
        }
        else {
            parent::write_yaml($obj, $modelname, $idx, $fields);
        }
    }


    /**
     * Load the whole yaml directory at once
     *
     * @param bool    $append
     */
    public function load_yaml($append=true) {
        /* delete TankFact.yml if we didn't write anything to it */
        if ($this->num_facts_written == 0) {
            unlink($this->output_dir.'/TankFact.yml');
        }

        Doctrine::loadData($this->output_dir, $append);
    }


}
